%%%-------------------------------------------------------------------
%%% File    : gtable.erl
%%% Author  : alfonso <alfonso@alfonso-laptop>
%%% Description : 
%%%
%%% Created :  {% now "jS F Y H:i" %}
%%%-------------------------------------------------------------------

%%% @author This is an automated generated file
%%% @doc 
%%% This is a file representing the table {{table}}
%%% Created on {% now "jS F Y H:i" %}
%%% @end

-module({{module}}).

-include("{{project}}.hrl").

%% API
-export([   
   {% for i in columns %}
   get{{i.name|capfirst}}/1,
   set{{i.name|capfirst}}/2,
   {% endfor %}   

   {% for i in fks %}
   get{{i.type|capfirst}}By{{i.name|capfirst}}/1,
   set{{i.type|capfirst}}By{{i.name|capfirst}}/2,
   {% endfor %}

{% for i in inverse_fks %}
   getListOf{{i.type|capfirst}}By{{i.foreign_key_column|capfirst}}/1,
   setListOf{{i.type|capfirst}}By{{i.foreign_key_column|capfirst}}/2,
{% endfor %}


   id/1,
   id_columns/0,
   select/0,
   select/1,
   select/2,
   columns/0,
   get_data/1,
   init/2,
   compare/2,
   modified/1,
   set_session/2,
   update/1,
   insert/1,insert/2,
   delete/1,								     
   mark_to_delete/1,
   commit/1,
   typeOf/1,					 
   insertAndRetrieve/1,insertAndRetrieve/2
  ]).

set_session(NewRef,R)->
    R#{{record}}{session = NewRef}.

columns()->
    [
     {% for i in columns %}
         "{{i.name}}",
      {% endfor %}
      ""].


{% for i in columns %}
typeOf({{i.name}}) ->
  {  {{i.type}} , {{i.type_size}} };
{% endfor %}
typeOf(_)->
    {undefined,undefined}.
    

select()->
    select("1=1").
select(Where)->
    select(Where, " 1 desc ").
select(Where, Order)->
    hiberl_session:get(?MODULE, "{{table}}", Where, Order ).

get_data(R)->
    [
     {% for i in columns %}
         R#{{record}}.{{i.name}},
      {% endfor %}
      ""].

init(Ref,Columns) ->
   State =
   #{{record}}{
     {% for i in columns %}
     {{i.name}} = hiberl_utils:happy_keysearch( "{{i.name}}", Columns),
     {% endfor %} 
     old_values = undefined
   },
   State#{{record}}{session = Ref, old_values = State,
		   hash = hash(State)}.


hash(R)->
    crypto:md5(hiberl_utils:sql_print(get_data(R))).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% Getters and Setters


id(R)->
    IDs = [
     {% for i in columns %}
     {% ifequal i.pk "true" %}
             R#{{record}}.{{i.name}},
     {% endifequal %}
     {% endfor %}
    []],
    lists:reverse(tl(lists:reverse(IDs))).

id_columns() ->
    IDs = [
     {% for i in columns %}
     {% ifequal i.pk "true" %}
             "{{i.name}}",
     {% endifequal %}
     {% endfor %}
    []],
    lists:reverse(tl(lists:reverse(IDs))).



{% for i in columns %}
%% @spec (R::{{module}}) -> {{i.type}}() 
%% @doc Retrieve the property {{i.name}} from record R
%% @end
get{{i.name|capfirst}}(R)->
    R#{{record}}.{{i.name}}.

%% @spec (R, NewValue) -> R
%% @doc Set the  property {{i.name}} 
%% @end
set{{i.name|capfirst}}(null,R) ->
    R#{{record}}{ {{i.name}} = null};
set{{i.name|capfirst}}(NewValue,R) 
{% ifequal i.type "integer" %}
   when is_integer(NewValue)
{% endifequal %}
{% ifequal i.type "float" %}
   when is_float(NewValue)
{% endifequal %}
{% ifequal i.type "string" %}
   when is_list(NewValue), length(NewValue) =< {{i.type_size}}
{% endifequal %} ->
    R#{{record}}{ {{i.name}} = NewValue};
set{{i.name|capfirst}}(_NewValue,_R) ->
    {error, { "{{i.name}} requires type: " , {{module}}:typeOf({{i.name}} ) }}.

{% endfor %}

{% for i in fks %}
get{{i.type|capfirst}}By{{i.name|capfirst}}(R) ->
    case R#{{record}}.{{i.type}}By{{i.name|capfirst}} of
	_ when R#{{record}}.{{i.name}} == null; R#{{record}}.{{i.name}} == undefined ->
	    {error, foreign_key_is_null};
	undefined->
	    hd({{i.type}}_dao:select(" {{i.foreign_key_column}} = " ++ hiberl_utils:sql_print(R#{{record}}.{{i.name}})));
	X -> X
    end.

set{{i.type|capfirst}}By{{i.name|capfirst}}(NewValue,R)->
    R#{{record}}{ {{i.name}} = NewValue#{{i.type}}.{{i.foreign_key_column}} }.
{% endfor %}


{% for i in inverse_fks %}
getListOf{{i.type|capfirst}}By{{i.foreign_key_column|capfirst}}(R) ->
    case R#{{record}}.{{i.type}}By{{i.foreign_key_column|capfirst}} of
	undefined->
	    {{i.type}}_dao:select(" {{i.foreign_key_column}} = " ++ hiberl_utils:sql_print(R#{{record}}.{{i.name}}));
	X -> X
    end.

setListOf{{i.type|capfirst}}By{{i.foreign_key_column|capfirst}}(ListValues,R) ->
    {error, not_implemented}.
{% endfor %}


update(R)->
    Filtered = zip_columns(R),
    OldL = lists:zip(?MODULE:id_columns(), ?MODULE:id(R#{{record}}.old_values)),
    Update1 = string:join( lists:map(fun({N,M})->[N,"=",hiberl_utils:sql_print(M)] end,Filtered) ," , "),      
    Update2 = string:join( lists:map(fun({N,M})->[N,"=",hiberl_utils:sql_print(M)] end, OldL )," AND "),   
    S = ["UPDATE {{table}} SET ",Update1," WHERE ",Update2],
    hiberl_session:execute_sql(R#{{record}}.session, S).


delete(R)->
     Filtered = zip_columns(R),
     OldL = zip_columns(R#{{record}}.old_values),
     Delete = string:join( lists:map(
			      fun({N,null})->[N," is NULL"];
				 ({N,M})->[N,"=",hiberl_utils:sql_print(M)] 
			      end,OldL) ," AND "),      
     S = ["DELETE {{table}} WHERE ",Delete],
     hiberl_session:execute_sql(R#{{record}}.session, S).

mark_to_delete(R)->
    R#{{record}}{to_delete_flag = true}.

insert(R)->
    insert(hiberl_session, R).
insert(Pid, R)->
     Filtered = zip_columns(R),
     Insert1 = string:join( lists:map(fun({N,_})->N end,Filtered) ,","),
     Insert2 = string:join( lists:map(fun({_,N})->hiberl_utils:sql_print(N) end,Filtered) ,","),
     S = ["INSERT INTO {{table}} (",Insert1,") VALUES (",Insert2,")"],
     hiberl_session:execute_sql(Pid, S).

insertAndRetrieve(R)->
    insertAndRetrieve(hiberl_session, R).
insertAndRetrieve(Pid,R)->
    {updated,1} = insert(Pid, R),
    case ?MODULE:id(R) of
	[undefined] ->
	    IdColumn = hd(?MODULE:id_columns()),
	    {selected,_,[{NewId}]} = hiberl_session:execute_sql(hiberl_session,  "SELECT LAST_INSERT_ID()"),
	    hd(?MODULE:select( [hiberl_utils:sql_print(IdColumn)," = ", NewId]));
	_ ->
	    {error,this_method_is_only_for_autoincrement_id}
    end.

commit(#{{record}}{to_delete_flag = true} = R)->
    delete(R);
commit(R)->
    case modified(R) of
	false -> ok;
	_ when R#{{record}}.old_values == undefined ->
	    insert(R);
	_->
	    update(R)
    end.
						      

zip_columns(R)->
    Columns = lists:zip({{module}}:columns(), [{% for i in columns %} 
     R#{{record}}.{{i.name}},
     {% endfor %}
     []]),
     F = fun({_,undefined}) -> false;
            ({[],_}) -> false;
            (_)->true
      end,
    lists:filter(F,Columns).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

compare(A,B) ->
{% for i in columns %}
	 (A#{{record}}.{{i.name}} == B#{{record}}.{{i.name}}) and
{% endfor %}
         true.

modified(A)->
    not compare(A#{{record}}.old_values,A).

%%modified(A)->
%    not (A#{{record}}.hash == hash(A)).
%%    not compare(A#{{record}}.old_values,A).

is_null(undefined) ->
    true;
is_null(_) ->false.
